﻿namespace lpr
{
    using System;
    using System.Runtime.InteropServices;

    internal sealed class SimpleLPRImpl : ISimpleLPR, IDisposable
    {
        private IntPtr _hEng;
        private Shimmy _shim = new Shimmy();

        public SimpleLPRImpl()
        {
            this._hEng = this._shim.Setup();
            if (this._hEng == IntPtr.Zero)
            {
                throw new Exception("Unable to create engine");
            }
        }

        private void check(bool bResult)
        {
            if (!bResult)
            {
                this.throwIfError();
            }
        }

        private void cleanup()
        {
            if (this._hEng != IntPtr.Zero)
            {
                this._shim.ReferenceCounted_release(this._hEng);
                this._hEng = IntPtr.Zero;
            }
            if (this._shim != null)
            {
                this._shim.Dispose();
                this._shim = null;
            }
        }

        public IProcessor createProcessor()
        {
            IntPtr hProc = this._shim.createProcessor(this._hEng);
            this.check(hProc != IntPtr.Zero);
            return new ProcessorImpl(this._shim, this._hEng, hProc);
        }

        public void Dispose()
        {
            this.cleanup();
            GC.SuppressFinalize(this);
        }

        ~SimpleLPRImpl()
        {
            this.cleanup();
        }

        public string get_countryCode(uint id)
        {
            string str;
            int num = this._shim.countryCode_get(this._hEng, id, out str);
            this.check(num > 0);
            return str;
        }

        public float get_countryWeight(string id)
        {
            float num;
            int num2 = this._shim.countryFromStringWeight_get(this._hEng, id, out num);
            this.check(num2 > 0);
            return num;
        }

        public float get_countryWeight(uint id)
        {
            float num;
            int num2 = this._shim.countryFromIdWeight_get(this._hEng, id, out num);
            this.check(num2 > 0);
            return num;
        }

        public void realizeCountryWeights()
        {
            int num = this._shim.realizeCountryWeights(this._hEng);
            this.check(num > 0);
        }

        public void set_countryWeight(string id, float val)
        {
            int num = this._shim.countryFromStringWeight_set(this._hEng, id, val);
            this.check(num > 0);
        }

        public void set_countryWeight(uint id, float val)
        {
            int num = this._shim.countryFromIdWeight_set(this._hEng, id, val);
            this.check(num > 0);
        }

        public void set_productKey(string productKeyPath)
        {
            this._shim.productKeyFromFile_set(this._hEng, "TEST");
            this.check(true);
        }

        public void set_productKey(byte[] productKey)
        {
            GCHandle handle = GCHandle.Alloc(productKey, GCHandleType.Pinned);
            this._shim.productKeyFromBuffer_set(this._hEng, handle.AddrOfPinnedObject(), (uint) productKey.GetLength(0));
            handle.Free();
            this.check(true);
        }

        private void throwIfError()
        {
            IntPtr hErrInfo = this._shim.lastError_get(this._hEng, 1);
            if (hErrInfo != IntPtr.Zero)
            {
                Exception exception = new Exception(this._shim.ErrorInfo_description_get(hErrInfo));
                this._shim.ReferenceCounted_release(hErrInfo);
                throw exception;
            }
        }

        public uint numSupportedCountries
        {
            get
            {
                return this._shim.numSupportedCountries_get(this._hEng);
            }
        }
    }
}

